/* eslint-disable react/no-danger */
/* eslint-disable @typescript-eslint/no-unused-vars */
import React, { useRef } from 'react';
import { Collapse } from 'antd';
import hljs from 'highlight.js';
import MarkdownIt from 'markdown-it';
import 'highlight.js/styles/atom-one-light.css';
import summary from '@/assets/images/advanceReact/summary-page1.png';
import './index.less';

const { Panel } = Collapse;
const REACT_ELEMENT_TYPE = Symbol(React.element);
const RESERVED_PROPS = {};
const mdParser = MarkdownIt({
  html: true,
  linkify: true,
  typographer: true,
  highlight(str, lang) {
    if (lang && hljs.getLanguage(lang)) {
      try {
        return hljs.highlight(lang, str).value;
      } catch (error) {
        console.log(error);
      }
    }
    return ''; // 使用额外的默认转义
  },
});

export default function Jsx() {
  const hasValidRef = () => {};
  const hasValidKey = () => {};
  const ReactCurrentOwner = useRef({});

  /**
   * @description: React.createElement
   * @param {*} type 标志节点类型/组件类型
   * @param {*} config 组件所有的属性以键值对存储在这
   * @param {*} children 组件之间的嵌套内容（子节点、子元素）
   */
  const createElement = (type, config, ...rest) => {
    // 存储后面需要用到的元素属性
    let propName;

    // props变量用于存储元素属性的键值对集合
    const props = {};

    // key、ref、self、source均为React元素的属性
    let key = null;
    let ref = null;
    let self = null;
    let source = null;

    // config对象中存储的是元素的属性
    if (config !== null) {
      // 依次初始化ref、key、self和source
      if (hasValidRef(config)) {
        ref = config.ref;
      }
    }
    // 序列化key
    if (hasValidKey(config)) {
      key = `${config.key}`;
    }
    self = config.__self === undefined ? null : config.__self;
    source = config.__source === undefined ? null : config.__source;

    // 然后把config里的属性放到props里
    for (propName in config) {
      if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
        props[propName] = config[propName];
      }
    }

    const childrenLength = rest.length;
    if (childrenLength === 1) {
      props.children = rest;
    }
    if (childrenLength > 1) {
      const childArr = Array(childrenLength);

      for (let i = 0; i < childrenLength; i++) {
        childArr[i] = rest[i + 2];
      }
      props.children = childArr;
    }

    return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
  };

  // 也就是虚拟DOM
  const ReactElement = (type, key, ref, self, source, owner, props) => {
    const element = {
      // 标识该对象是一个ReactElement
      $$typeof: REACT_ELEMENT_TYPE,

      // 内置属性
      type,
      key,
      ref,
      props,

      // 记录创建该元素的组件
      _owner: owner,
    };
    // if(__DEV__) {}
    return element;
  };

  /**
   * @description: ReactDOm.render 把虚拟DOM转换为真实DOM
   * @param {*} element ReactElement
   * @param {*} container 元素挂载容器（真实DOM）
   * @param {*} callback 处理选后的回掉函数
   */
  const render = (element, container, callback) => {};

  const code =
    '```js' +
    `
    const REACT_ELEMENT_TYPE = Symbol(React.element);
    const RESERVED_PROPS = {};

    const hasValidRef = () => {};
    const hasValidKey = () => {};
    const ReactCurrentOwner = useRef({});

    /**
     * @description: React.createElement
     * @param {*} type 标志节点类型/组件类型
     * @param {*} config 组件所有的属性以键值对存储在这
     * @param {*} children 组件之间的嵌套内容（子节点、子元素）
     */
    const createElement = (type, config, ...rest) => {
      // 存储后面需要用到的元素属性
      let propName;

      // props变量用于存储元素属性的键值对集合
      const props = {};

      // key、ref、self、source均为React元素的属性
      let key = null;
      let ref = null;
      let self = null;
      let source = null;

      // config对象中存储的是元素的属性
      if (config !== null) {
        // 依次初始化ref、key、self和source
        if (hasValidRef(config)) {
          ref = config.ref;
        }
      }
      // 序列化key
      if (hasValidKey(config)) {
        key = config.key + '';
      }
      self = config.__self === undefined ? null : config.__self;
      source = config.__source === undefined ? null : config.__source;

      // 然后把config里的属性放到props里
      for (propName in config) {
        if (hasOwnProperty.call(config, propName) && !RESERVED_PROPS.hasOwnProperty(propName)) {
          props[propName] = config[propName];
        }
      }

      const childrenLength = rest.length;
      if (childrenLength === 1) {
        props.children = rest;
      }
      if (childrenLength > 1) {
        const childArr = Array(childrenLength);

        for (let i = 0; i < childrenLength; i++) {
          childArr[i] = rest[i + 2];
        }
        props.children = childArr;
      }

      return ReactElement(type, key, ref, self, source, ReactCurrentOwner.current, props);
    };

    // 也就是虚拟DOM
    const ReactElement = (type, key, ref, self, source, owner, props) => {
      const element = {
        // 标识该对象是一个ReactElement
        $$typeof: REACT_ELEMENT_TYPE,

        // 内置属性
        type,
        key,
        ref,
        props,

        // 记录创建该元素的组件
        _owner: owner,
      };
      // if(__DEV__) {}
      return element;
    };

    /**
     * @description: ReactDOm.render 把虚拟DOM转换为真实DOM
     * @param {*} element ReactElement
     * @param {*} container 元素挂载容器（真实DOM）
     * @param {*} callback 处理选后的回掉函数
     */
    const render = (element, container, callback) => { };
  `;
  return (
    <div>
      <Collapse defaultActiveKey={['1', '2', '3']}>
        <Panel header="1、JSX的本质是什么，它和JS之间的关系" key="1">
          <p>JSX是JavaScript的一种语法打展，它和模板语言很接近，但是它充分具备JavaScript的能力。</p>
          <p>
            Babel是个工具链， 主要用于将ECMAScript
            2015+版本的代码转换为向后兼容的JavaScript语法，以便能够运行在当前和旧版本的浏览器或其他环境中。
          </p>
          <p>
            JSX会被Babel编译为React.createElement(), React.createElement()将返回一个叫作“React
            Element”的JS对象。
          </p>
        </Panel>
        <Panel header="为什么要用JSX？不用会有什么后果" key="2">
          <p>
            上述说到，他的本质还是调用React.createElement这个api，JSX只是个语法糖，写法简洁，大大提高工作效率，如果不使用JSX，当元素层级较深时，用React.createElement
            进行创建话，代码不够清晰，给人一种杂糅感，写起来也费劲。
          </p>
        </Panel>
        <Panel header="JSX背后的功能模块是什么，这个功能模块做了哪些事" key="3">
          <div
            className="code-wrapper"
            dangerouslySetInnerHTML={{
              __html: mdParser.render(code),
            }}
          />
        </Panel>
      </Collapse>
      <img src={summary} alt="" width="100%" style={{ marginTop: 20 }} />
    </div>
  );
}
